package model;

import java.util.ArrayList;
import java.util.List;

import math.RMSE;
import data.DataBig;

public class PredictBig {
	List<DataBig> list = new ArrayList<DataBig>();
	double allRMSE;
	double posRMSE;
	double neuRMSE;
	double negRMSE;

	public PredictBig(List<DataBig> test, MFBig mf){
		int k = mf.getK();
		double avg = mf.getAvgTrain();
		double[] ubias = mf.getUbias();
		double[] ibias = mf.getIbias();
		double[] ufactor = mf.getUfactor();
		double[] ifactor = mf.getIfactor();
		
		double allSSE = 0;
		
		for(DataBig data : test){
			int uid = data.uid;
			int iid = data.iid;
			double rat = data.rat;
			
			double pred = 0;
			pred += avg;
			pred += ubias[uid-1];
			pred += ibias[iid-1];
			
			for(int j=0; j<k; j++){
				pred += ufactor[(uid-1)*k+j]*ifactor[(iid-1)*k+j];
			}
			
			double SE = (rat - pred) * (rat - pred);
			allSSE += SE; 
			
//			list.add(new DataBig(uid,iid,pred));
		}

		this.allRMSE = Math.sqrt(allSSE / test.size());
//		this.allRMSE = RMSE.RMSE(test, avg, ubias, ibias, ufactor, ifactor, (byte) k);
	}
	
	public PredictBig(List<DataBig> postest, List<DataBig> negtest, List<DataBig> neutest, MFBig mf, MFBig pmf, MFBig nmf){
		int k = mf.getK();
		double avg = mf.getAvgTrain();
		double[] ubias = mf.getUbias();
		double[] ibias = mf.getIbias();
		double[] ufactor = mf.getUfactor();
		double[] ifactor = mf.getIfactor();

		double pavg = pmf.getAvgTrain();
		double[] uposbias = pmf.getUbias();
		double[] iposbias = pmf.getIbias();
		double[] uposfactor = pmf.getUfactor();
		double[] iposfactor = pmf.getIfactor();		

		double navg = nmf.getAvgTrain();
		double[] unegbias = nmf.getUbias();
		double[] inegbias = nmf.getIbias();
		double[] unegfactor = nmf.getUfactor();
		double[] inegfactor = nmf.getIfactor();
		
		double allSSE = 0;
		double posSSE = 0;
		double neuSSE = 0;
		double negSSE = 0;
		int size = postest.size() + negtest.size() + neutest.size();
		
		for(DataBig data : postest){
			int uid = data.uid;
			int iid = data.iid;
			double rat = data.rat;
			
			double pred = 0;
			pred += pavg;
			pred += uposbias[uid-1];
			pred += iposbias[iid-1];
			
			for(int j=0; j<k; j++){
				pred += uposfactor[(uid-1)*k+j]*iposfactor[(iid-1)*k+j];
			}
			
			double SE = (rat - pred) * (rat - pred);
			posSSE += SE;
			allSSE += SE; 
			
			list.add(new DataBig(uid,iid,pred));
		}
		
		for(DataBig data : neutest){
			int uid = data.uid;
			int iid = data.iid;
			double rat = data.rat;
			
			double pred = 0;
			pred += avg;
			pred += ubias[uid-1];
			pred += ibias[iid-1];
			
			for(int j=0; j<k; j++){
				pred += ufactor[(uid-1)*k+j]*ifactor[(iid-1)*k+j];
			}
			
			double SE = (rat - pred) * (rat - pred);
			neuSSE += SE;
			allSSE += SE; 
			
			list.add(new DataBig(uid,iid,pred));
		}
		
		for(DataBig data : negtest){
			int uid = data.uid;
			int iid = data.iid;
			double rat = data.rat;
			
			double pred = 0;
			pred += navg;
			pred += unegbias[uid-1];
			pred += inegbias[iid-1];
			
			for(int j=0; j<k; j++){
				pred += unegfactor[(uid-1)*k+j]*inegfactor[(iid-1)*k+j];
			}
			
			double SE = (rat - pred) * (rat - pred);
			negSSE += SE;
			allSSE += SE; 
			
			list.add(new DataBig(uid,iid,pred));
		}
		
		this.allRMSE = RMSE.RMSE(postest, negtest, neutest, avg, ubias, ibias, ufactor, ifactor, 
				pavg, uposbias, iposbias, uposfactor, iposfactor, 
				navg, unegbias, inegbias, unegfactor, inegfactor, (byte) k);
		
		this.posRMSE = RMSE.RMSE(postest, pavg, uposbias, iposbias, uposfactor, iposfactor, (byte) k);
		this.neuRMSE = RMSE.RMSE(neutest, avg, ubias, ibias, ufactor, ifactor, (byte) k);
		this.negRMSE = RMSE.RMSE(negtest, navg, unegbias, inegbias, unegfactor, inegfactor, (byte) k);
		
//		this.allRMSE = Math.sqrt(allSSE / size);
//		this.posRMSE = Math.sqrt(posSSE / postest.size());
//		this.neuRMSE = Math.sqrt(neuSSE / neutest.size());
//		this.negRMSE = Math.sqrt(negSSE / negtest.size());
	}
	
	public List<DataBig> getList() {
		return list;
	}

	public double getAllRMSE() {
		return allRMSE;
	}

	public double getPosRMSE() {
		return posRMSE;
	}

	public double getNeuRMSE() {
		return neuRMSE;
	}

	public double getNegRMSE() {
		return negRMSE;
	}
}
